home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / var / lib / python-support / python2.6 / debian_bundle / changelog.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  26.7 KB  |  667 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. '''This module implements facilities to deal with Debian changelogs.'''
  5. import re
  6. import unittest
  7. import warnings
  8. import debian_support
  9.  
  10. class ChangelogParseError(StandardError):
  11.     '''Indicates that the changelog could not be parsed'''
  12.     is_user_error = True
  13.     
  14.     def __init__(self, line):
  15.         self._line = line
  16.  
  17.     
  18.     def __str__(self):
  19.         return 'Could not parse changelog: ' + self._line
  20.  
  21.  
  22.  
  23. class ChangelogCreateError(StandardError):
  24.     '''Indicates that changelog could not be created, as all the information
  25.     required was not given'''
  26.     pass
  27.  
  28.  
  29. class VersionError(StandardError):
  30.     '''Indicates that the version does not conform to the required format'''
  31.     is_user_error = True
  32.     
  33.     def __init__(self, version):
  34.         self._version = version
  35.  
  36.     
  37.     def __str__(self):
  38.         return 'Could not parse version: ' + self._version
  39.  
  40.  
  41.  
  42. class Version(debian_support.Version, object):
  43.     '''Represents a version of a Debian package.'''
  44.     
  45.     def __init__(self, version):
  46.         version = str(version)
  47.         debian_support.Version.__init__(self, version)
  48.         self.full_version = version
  49.  
  50.     
  51.     def __setattr__(self, attr, value):
  52.         """Update all the attributes, given a particular piece of the version
  53.   
  54.       Allowable values for attr, hopefully self-explanatory:
  55.         full_version
  56.         epoch
  57.         upstream_version
  58.         debian_version
  59.  
  60.       Any attribute starting with __ is given to object's __setattr__ method.
  61.       """
  62.         attrs = ('full_version', 'epoch', 'upstream_version', 'debian_version')
  63.         if attr.startswith('_Version__'):
  64.             object.__setattr__(self, attr, value)
  65.             return None
  66.         if attr not in attrs:
  67.             raise AttributeError('Cannot assign to attribute ' + attr)
  68.         attr not in attrs
  69.         if attr == 'full_version':
  70.             version = value
  71.             p = re.compile('^(?:(?P<epoch>\\d+):)?' + '(?P<upstream_version>[A-Za-z0-9.+:~-]+?)' + '(?:-(?P<debian_version>[A-Za-z0-9.~+]+))?$')
  72.             m = p.match(version)
  73.             if m is None:
  74.                 raise VersionError(version)
  75.             m is None
  76.             for key, value in m.groupdict().items():
  77.                 object.__setattr__(self, key, value)
  78.             
  79.             self._Version__asString = version
  80.         else:
  81.             d = { }
  82.             for a in attrs[1:]:
  83.                 if a == attr:
  84.                     d[a] = value
  85.                     continue
  86.                 d[a] = getattr(self, a)
  87.             
  88.             version = ''
  89.             if d['epoch'] and d['epoch'] != '0':
  90.                 version += d['epoch'] + ':'
  91.             
  92.             version += d['upstream_version']
  93.             if d['debian_version']:
  94.                 version += '-' + d['debian_version']
  95.             
  96.             self.full_version = version
  97.  
  98.     full_version = property((lambda self: self._Version__asString))
  99.  
  100.  
  101. class ChangeBlock(object):
  102.     '''Holds all the information about one block from the changelog.'''
  103.     
  104.     def __init__(self, package = None, version = None, distributions = None, urgency = None, urgency_comment = None, changes = None, author = None, date = None, other_pairs = None):
  105.         self._raw_version = None
  106.         self._set_version(version)
  107.         self.package = package
  108.         self.distributions = distributions
  109.         if not urgency:
  110.             pass
  111.         self.urgency = 'unknown'
  112.         if not urgency_comment:
  113.             pass
  114.         self.urgency_comment = ''
  115.         self._changes = changes
  116.         self.author = author
  117.         self.date = date
  118.         self._trailing = []
  119.         if not other_pairs:
  120.             pass
  121.         self.other_pairs = { }
  122.         self._no_trailer = False
  123.         self._trailer_separator = '  '
  124.  
  125.     
  126.     def _set_version(self, version):
  127.         if version is not None:
  128.             self._raw_version = str(version)
  129.         
  130.  
  131.     
  132.     def _get_version(self):
  133.         return Version(self._raw_version)
  134.  
  135.     version = property(_get_version, _set_version)
  136.     
  137.     def other_keys_normalised(self):
  138.         norm_dict = { }
  139.         for key, value in other_pairs.items():
  140.             key = key[0].upper() + key[1:].lower()
  141.             m = xbcs_re.match(key)
  142.             if m is None:
  143.                 key = 'XS-%s' % key
  144.             
  145.             norm_dict[key] = value
  146.         
  147.         return norm_dict
  148.  
  149.     
  150.     def changes(self):
  151.         return self._changes
  152.  
  153.     
  154.     def add_trailing_line(self, line):
  155.         self._trailing.append(line)
  156.  
  157.     
  158.     def add_change(self, change):
  159.         if self._changes is None:
  160.             self._changes = [
  161.                 change]
  162.         else:
  163.             changes = self._changes
  164.             changes.reverse()
  165.             added = False
  166.             for i in range(len(changes)):
  167.                 m = blankline.match(changes[i])
  168.                 if m is None:
  169.                     changes.insert(i, change)
  170.                     added = True
  171.                     break
  172.                     continue
  173.             
  174.             changes.reverse()
  175.             if not added:
  176.                 changes.append(change)
  177.             
  178.             self._changes = changes
  179.  
  180.     
  181.     def __str__(self):
  182.         block = ''
  183.         if self.package is None:
  184.             raise ChangelogCreateError('Package not specified')
  185.         self.package is None
  186.         block += self.package + ' '
  187.         if self._raw_version is None:
  188.             raise ChangelogCreateError('Version not specified')
  189.         self._raw_version is None
  190.         block += '(' + self._raw_version + ') '
  191.         if self.distributions is None:
  192.             raise ChangelogCreateError('Distribution not specified')
  193.         self.distributions is None
  194.         block += self.distributions + '; '
  195.         if self.urgency is None:
  196.             raise ChangelogCreateError('Urgency not specified')
  197.         self.urgency is None
  198.         block += 'urgency=' + self.urgency + self.urgency_comment
  199.         for key, value in self.other_pairs.items():
  200.             block += ', %s=%s' % (key, value)
  201.         
  202.         block += '\n'
  203.         if self.changes() is None:
  204.             raise ChangelogCreateError('Changes not specified')
  205.         self.changes() is None
  206.         for change in self.changes():
  207.             block += change + '\n'
  208.         
  209.         if not self._no_trailer:
  210.             if self.author is None:
  211.                 raise ChangelogCreateError('Author not specified')
  212.             self.author is None
  213.             if self.date is None:
  214.                 raise ChangelogCreateError('Date not specified')
  215.             self.date is None
  216.             block += ' -- ' + self.author + self._trailer_separator + self.date + '\n'
  217.         
  218.         for line in self._trailing:
  219.             block += line + '\n'
  220.         
  221.         return block
  222.  
  223.  
  224. topline = re.compile('^(\\w%(name_chars)s*) \\(([^\\(\\) \\t]+)\\)((\\s+%(name_chars)s+)+)\\;' % {
  225.     'name_chars': '[-+0-9a-z.]' }, re.IGNORECASE)
  226. blankline = re.compile('^\\s*$')
  227. change = re.compile('^\\s\\s+.*$')
  228. endline = re.compile('^ -- (.*) <(.*)>(  ?)((\\w+\\,\\s*)?\\d{1,2}\\s+\\w+\\s+\\d{4}\\s+\\d{1,2}:\\d\\d:\\d\\d\\s+[-+]\\d{4}(\\s+\\([^\\\\(\\)]\\))?\\s*)$')
  229. endline_nodetails = re.compile('^ --(?: (.*) <(.*)>(  ?)((\\w+\\,\\s*)?\\d{1,2}\\s+\\w+\\s+\\d{4}\\s+\\d{1,2}:\\d\\d:\\d\\d\\s+[-+]\\d{4}(\\s+\\([^\\\\(\\)]\\))?))?\\s*$')
  230. keyvalue = re.compile('^([-0-9a-z]+)=\\s*(.*\\S)$', re.IGNORECASE)
  231. value_re = re.compile('^([-0-9a-z]+)((\\s+.*)?)$', re.IGNORECASE)
  232. xbcs_re = re.compile('^X[BCS]+-', re.IGNORECASE)
  233. emacs_variables = re.compile('^(;;\\s*)?Local variables:', re.IGNORECASE)
  234. vim_variables = re.compile('^vim:', re.IGNORECASE)
  235. cvs_keyword = re.compile('^\\$\\w+:.*\\$')
  236. comments = re.compile('^\\# ')
  237. more_comments = re.compile('^/\\*.*\\*/')
  238. old_format_re1 = re.compile('^(\\w+\\s+\\w+\\s+\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}\\s+[\\w\\s]*\\d{4})\\s+(.*)\\s+(<|\\()(.*)(\\)|>)')
  239. old_format_re2 = re.compile('^(\\w+\\s+\\w+\\s+\\d{1,2},?\\s*\\d{4})\\s+(.*)\\s+(<|\\()(.*)(\\)|>)')
  240. old_format_re3 = re.compile('^(\\w[-+0-9a-z.]*) \\(([^\\(\\) \t]+)\\)\\;?', re.IGNORECASE)
  241. old_format_re4 = re.compile('^([\\w.+-]+)(-| )(\\S+) Debian (\\S+)', re.IGNORECASE)
  242. old_format_re5 = re.compile('^Changes from version (.*) to (.*):', re.IGNORECASE)
  243. old_format_re6 = re.compile('^Changes for [\\w.+-]+-[\\w.+-]+:?\\s*$', re.IGNORECASE)
  244. old_format_re7 = re.compile('^Old Changelog:\\s*$', re.IGNORECASE)
  245. old_format_re8 = re.compile('^(?:\\d+:)?\\w[\\w.+~-]*:?\\s*$')
  246.  
  247. class Changelog(object):
  248.     '''Represents a debian/changelog file. You can ask it several things
  249.        about the file.
  250.     '''
  251.     
  252.     def __init__(self, file = None, max_blocks = None, allow_empty_author = False, strict = True):
  253.         '''Set up the Changelog for use. file is the contects of the
  254.            changelog.
  255.         '''
  256.         self._blocks = []
  257.         self.initial_blank_lines = []
  258.         if file is not None:
  259.             
  260.             try:
  261.                 self.parse_changelog(file, max_blocks = max_blocks, allow_empty_author = allow_empty_author, strict = strict)
  262.             except ChangelogParseError:
  263.                 pass
  264.             except:
  265.                 None<EXCEPTION MATCH>ChangelogParseError
  266.             
  267.  
  268.         None<EXCEPTION MATCH>ChangelogParseError
  269.  
  270.     
  271.     def _parse_error(self, message, strict):
  272.         if strict:
  273.             raise ChangelogParseError(message)
  274.         strict
  275.         warnings.warn(message)
  276.  
  277.     
  278.     def parse_changelog(self, file, max_blocks = None, allow_empty_author = False, strict = True):
  279.         first_heading = 'first heading'
  280.         next_heading_or_eof = 'next heading of EOF'
  281.         start_of_change_data = 'start of change data'
  282.         more_changes_or_trailer = 'more change data or trailer'
  283.         slurp_to_end = 'slurp to end'
  284.         self._blocks = []
  285.         self.initial_blank_lines = []
  286.         current_block = ChangeBlock()
  287.         changes = []
  288.         state = first_heading
  289.         old_state = None
  290.         if isinstance(file, basestring):
  291.             if file[-1] != '\n':
  292.                 file += '\n'
  293.             
  294.             file = file.split('\n')[:-1]
  295.         
  296.         for line in file:
  297.             if state == first_heading or state == next_heading_or_eof:
  298.                 top_match = topline.match(line)
  299.                 blank_match = blankline.match(line)
  300.                 if top_match is not None:
  301.                     if max_blocks is not None and len(self._blocks) >= max_blocks:
  302.                         return None
  303.                     current_block.package = top_match.group(1)
  304.                     current_block._raw_version = top_match.group(2)
  305.                     current_block.distributions = top_match.group(3).lstrip()
  306.                     pairs = line.split(';', 1)[1]
  307.                     all_keys = { }
  308.                     other_pairs = { }
  309.                     for pair in pairs.split(','):
  310.                         pair = pair.strip()
  311.                         kv_match = keyvalue.match(pair)
  312.                         if kv_match is None:
  313.                             self._parse_error("Invalid key-value pair after ';': %s" % pair, strict)
  314.                             continue
  315.                         
  316.                         key = kv_match.group(1)
  317.                         value = kv_match.group(2)
  318.                         if key.lower() in all_keys:
  319.                             self._parse_error('Repeated key-value: %s' % key.lower(), strict)
  320.                         
  321.                         all_keys[key.lower()] = value
  322.                         if key.lower() == 'urgency':
  323.                             val_match = value_re.match(value)
  324.                         None if val_match is None else comment is not None
  325.                         other_pairs[key] = value
  326.                     
  327.                     current_block.other_pairs = other_pairs
  328.                     state = start_of_change_data
  329.                 elif blank_match is not None:
  330.                     if state == first_heading:
  331.                         self.initial_blank_lines.append(line)
  332.                     else:
  333.                         self._blocks[-1].add_trailing_line(line)
  334.                 else:
  335.                     emacs_match = emacs_variables.match(line)
  336.                     vim_match = vim_variables.match(line)
  337.                     cvs_match = cvs_keyword.match(line)
  338.                     comments_match = comments.match(line)
  339.                     more_comments_match = more_comments.match(line)
  340.                     if (emacs_match is not None or vim_match is not None) and state != first_heading:
  341.                         self._blocks[-1].add_trailing_line(line)
  342.                         old_state = state
  343.                         state = slurp_to_end
  344.                         continue
  345.                     
  346.                     if cvs_match is not None and comments_match is not None or more_comments_match is not None:
  347.                         if state == first_heading:
  348.                             self.initial_blank_lines.append(line)
  349.                             continue
  350.                         self._blocks[-1].add_trailing_line(line)
  351.                         continue
  352.                     
  353.                     if (old_format_re1.match(line) is not None and old_format_re2.match(line) is not None and old_format_re3.match(line) is not None and old_format_re4.match(line) is not None and old_format_re5.match(line) is not None and old_format_re6.match(line) is not None and old_format_re7.match(line) is not None or old_format_re8.match(line) is not None) and state != first_heading:
  354.                         self._blocks[-1].add_trailing_line(line)
  355.                         old_state = state
  356.                         state = slurp_to_end
  357.                         continue
  358.                     
  359.                     self._parse_error('Unexpected line while looking for %s: %s' % (state, line), strict)
  360.                     if state == first_heading:
  361.                         self.initial_blank_lines.append(line)
  362.                     else:
  363.                         self._blocks[-1].add_trailing_line(line)
  364.             state == first_heading
  365.             if state == start_of_change_data or state == more_changes_or_trailer:
  366.                 change_match = change.match(line)
  367.                 end_match = endline.match(line)
  368.                 end_no_details_match = endline_nodetails.match(line)
  369.                 blank_match = blankline.match(line)
  370.                 if change_match is not None:
  371.                     changes.append(line)
  372.                     state = more_changes_or_trailer
  373.                 elif end_match is not None:
  374.                     if end_match.group(3) != '  ':
  375.                         self._parse_error('Badly formatted trailer line: %s' % line, strict)
  376.                         current_block._trailer_separator = end_match.group(3)
  377.                     
  378.                     current_block.author = '%s <%s>' % (end_match.group(1), end_match.group(2))
  379.                     current_block.date = end_match.group(4)
  380.                     current_block._changes = changes
  381.                     self._blocks.append(current_block)
  382.                     changes = []
  383.                     current_block = ChangeBlock()
  384.                     state = next_heading_or_eof
  385.                 elif end_no_details_match is not None:
  386.                     if not allow_empty_author:
  387.                         self._parse_error('Badly formatted trailer line: %s' % line, strict)
  388.                         continue
  389.                     
  390.                     current_block._changes = changes
  391.                     self._blocks.append(current_block)
  392.                     changes = []
  393.                     current_block = ChangeBlock()
  394.                     state = next_heading_or_eof
  395.                 elif blank_match is not None:
  396.                     changes.append(line)
  397.                 else:
  398.                     cvs_match = cvs_keyword.match(line)
  399.                     comments_match = comments.match(line)
  400.                     more_comments_match = more_comments.match(line)
  401.                     if cvs_match is not None and comments_match is not None or more_comments_match is not None:
  402.                         changes.append(line)
  403.                         continue
  404.                     
  405.                     self._parse_error('Unexpected line while looking for %s: %s' % (state, line), strict)
  406.                     changes.append(line)
  407.             change_match is not None
  408.             if state == slurp_to_end:
  409.                 if old_state == next_heading_or_eof:
  410.                     self._blocks[-1].add_trailing_line(line)
  411.                 else:
  412.                     changes.append(line)
  413.             old_state == next_heading_or_eof
  414.             if not False:
  415.                 raise AssertionError, 'Unknown state: %s' % state
  416.         
  417.         if (state != next_heading_or_eof or state != slurp_to_end or state == slurp_to_end) and old_state != next_heading_or_eof:
  418.             self._parse_error('Found eof where expected %s' % state, strict)
  419.             current_block._changes = changes
  420.             current_block._no_trailer = True
  421.             self._blocks.append(current_block)
  422.         
  423.  
  424.     
  425.     def get_version(self):
  426.         '''Return a Version object for the last version'''
  427.         return self._blocks[0].version
  428.  
  429.     
  430.     def set_version(self, version):
  431.         '''Set the version of the last changelog block
  432.  
  433.         version can be a full version string, or a Version object
  434.         '''
  435.         self._blocks[0].version = Version(version)
  436.  
  437.     version = property(get_version, set_version, doc = 'Version object for last changelog block')
  438.     full_version = property((lambda self: self.version.full_version))
  439.     epoch = property((lambda self: self.version.epoch))
  440.     debian_version = property((lambda self: self.version.debian_version))
  441.     upstream_version = property((lambda self: self.version.upstream_version))
  442.     
  443.     def get_package(self):
  444.         '''Returns the name of the package in the last version.'''
  445.         return self._blocks[0].package
  446.  
  447.     
  448.     def set_package(self, package):
  449.         self._blocks[0].package = package
  450.  
  451.     package = property(get_package, set_package, doc = 'Name of the package in the last version')
  452.     
  453.     def get_versions(self):
  454.         '''Returns a list of version objects that the package went through.'''
  455.         return [ block.version for block in self._blocks ]
  456.  
  457.     versions = property(get_versions, doc = 'List of version objects the package went through')
  458.     
  459.     def _raw_versions(self):
  460.         return [ block._raw_version for block in self._blocks ]
  461.  
  462.     
  463.     def __str__(self):
  464.         cl = '\n'.join(self.initial_blank_lines)
  465.         for block in self._blocks:
  466.             cl += str(block)
  467.         
  468.         return cl
  469.  
  470.     
  471.     def set_distributions(self, distributions):
  472.         self._blocks[0].distributions = distributions
  473.  
  474.     distributions = property((lambda self: self._blocks[0].distributions), set_distributions)
  475.     
  476.     def set_urgency(self, urgency):
  477.         self._blocks[0].urgency = urgency
  478.  
  479.     urgency = property((lambda self: self._blocks[0].urgency), set_urgency)
  480.     
  481.     def add_change(self, change):
  482.         self._blocks[0].add_change(change)
  483.  
  484.     
  485.     def set_author(self, author):
  486.         self._blocks[0].author = author
  487.  
  488.     author = property((lambda self: self._blocks[0].author), set_author)
  489.     
  490.     def set_date(self, date):
  491.         self._blocks[0].date = date
  492.  
  493.     date = property((lambda self: self._blocks[0].date), set_date)
  494.     
  495.     def new_block(self, **kwargs):
  496.         block = ChangeBlock(**kwargs)
  497.         block.add_trailing_line('')
  498.         self._blocks.insert(0, block)
  499.  
  500.     
  501.     def write_to_open_file(self, file):
  502.         file.write(self.__str__())
  503.  
  504.  
  505.  
  506. def _test():
  507.     import doctest
  508.     doctest.testmod()
  509.     unittest.main()
  510.  
  511.  
  512. class ChangelogTests(unittest.TestCase):
  513.     
  514.     def test_create_changelog(self):
  515.         c = open('test_changelog').read()
  516.         cl = Changelog(c)
  517.         cs = str(cl)
  518.         clines = c.split('\n')
  519.         cslines = cs.split('\n')
  520.         for i in range(len(clines)):
  521.             self.assertEqual(clines[i], cslines[i])
  522.         
  523.         self.assertEqual(len(clines), len(cslines), 'Different lengths')
  524.  
  525.     
  526.     def test_create_changelog_single_block(self):
  527.         c = open('test_changelog').read()
  528.         cl = Changelog(c, max_blocks = 1)
  529.         cs = str(cl)
  530.         self.assertEqual(cs, 'gnutls13 (1:1.4.1-1) unstable; urgency=HIGH\n\n  [ James Westby ]\n  * New upstream release.\n  * Remove the following patches as they are now included upstream:\n    - 10_certtoolmanpage.diff\n    - 15_fixcompilewarning.diff\n    - 30_man_hyphen_*.patch\n  * Link the API reference in /usr/share/gtk-doc/html as gnutls rather than\n    gnutls-api so that devhelp can find it.\n\n -- Andreas Metzler <ametzler@debian.org>  Sat, 15 Jul 2006 11:11:08 +0200\n\n')
  531.  
  532.     
  533.     def test_modify_changelog(self):
  534.         c = open('test_modify_changelog1').read()
  535.         cl = Changelog(c)
  536.         cl.package = 'gnutls14'
  537.         cl.version = '1:1.4.1-2'
  538.         cl.distributions = 'experimental'
  539.         cl.urgency = 'medium'
  540.         cl.add_change('  * Add magic foo')
  541.         cl.author = 'James Westby <jw+debian@jameswestby.net>'
  542.         cl.date = 'Sat, 16 Jul 2008 11:11:08 -0200'
  543.         c = open('test_modify_changelog2').read()
  544.         clines = c.split('\n')
  545.         cslines = str(cl).split('\n')
  546.         for i in range(len(clines)):
  547.             self.assertEqual(clines[i], cslines[i])
  548.         
  549.         self.assertEqual(len(clines), len(cslines), 'Different lengths')
  550.  
  551.     
  552.     def test_add_changelog_section(self):
  553.         c = open('test_modify_changelog2').read()
  554.         cl = Changelog(c)
  555.         cl.new_block(package = 'gnutls14', version = Version('1:1.4.1-3'), distributions = 'experimental', urgency = 'low', author = 'James Westby <jw+debian@jameswestby.net>')
  556.         self.assertRaises(ChangelogCreateError, cl.__str__)
  557.         cl.set_date('Sat, 16 Jul 2008 11:11:08 +0200')
  558.         cl.add_change('')
  559.         cl.add_change('  * Foo did not work, let us try bar')
  560.         cl.add_change('')
  561.         c = open('test_modify_changelog3').read()
  562.         clines = c.split('\n')
  563.         cslines = str(cl).split('\n')
  564.         for i in range(len(clines)):
  565.             self.assertEqual(clines[i], cslines[i])
  566.         
  567.         self.assertEqual(len(clines), len(cslines), 'Different lengths')
  568.  
  569.     
  570.     def test_strange_changelogs(self):
  571.         ''' Just opens and parses a strange changelog '''
  572.         c = open('test_strange_changelog').read()
  573.         cl = Changelog(c)
  574.  
  575.     
  576.     def test_set_version_with_string(self):
  577.         c1 = Changelog(open('test_modify_changelog1').read())
  578.         c2 = Changelog(open('test_modify_changelog1').read())
  579.         c1.version = '1:2.3.5-2'
  580.         c2.version = Version('1:2.3.5-2')
  581.         self.assertEqual(c1.version, c2.version)
  582.         self.assertEqual((c1.full_version, c1.epoch, c1.upstream_version, c1.debian_version), (c2.full_version, c2.epoch, c2.upstream_version, c2.debian_version))
  583.  
  584.     
  585.     def test_changelog_no_author(self):
  586.         cl_no_author = 'gnutls13 (1:1.4.1-1) unstable; urgency=low\n\n  * New upstream release.\n\n --\n'
  587.         c1 = Changelog()
  588.         c1.parse_changelog(cl_no_author, allow_empty_author = True)
  589.         self.assertEqual(c1.author, None)
  590.         self.assertEqual(c1.date, None)
  591.         self.assertEqual(c1.package, 'gnutls13')
  592.         c2 = Changelog()
  593.         self.assertRaises(ChangelogParseError, c2.parse_changelog, cl_no_author)
  594.  
  595.     
  596.     def test_magic_version_properties(self):
  597.         c = Changelog(open('test_changelog'))
  598.         self.assertEqual(c.debian_version, '1')
  599.         self.assertEqual(c.full_version, '1:1.4.1-1')
  600.         self.assertEqual(c.upstream_version, '1.4.1')
  601.         self.assertEqual(c.epoch, '1')
  602.         self.assertEqual(str(c.version), c.full_version)
  603.  
  604.     
  605.     def test_allow_full_stops_in_distribution(self):
  606.         c = Changelog(open('test_changelog_full_stops'))
  607.         self.assertEqual(c.debian_version, None)
  608.         self.assertEqual(c.full_version, '1.2.3')
  609.         self.assertEqual(str(c.version), c.full_version)
  610.  
  611.  
  612.  
  613. class VersionTests(unittest.TestCase):
  614.     
  615.     def _test_version(self, full_version, epoch, upstream, debian):
  616.         v = Version(full_version)
  617.         self.assertEqual(v.full_version, full_version, 'Full version broken')
  618.         self.assertEqual(v.epoch, epoch, 'Epoch broken')
  619.         self.assertEqual(v.upstream_version, upstream, 'Upstram broken')
  620.         self.assertEqual(v.debian_version, debian, 'Debian broken')
  621.  
  622.     
  623.     def testversions(self):
  624.         self._test_version('1:1.4.1-1', '1', '1.4.1', '1')
  625.         self._test_version('7.1.ds-1', None, '7.1.ds', '1')
  626.         self._test_version('10.11.1.3-2', None, '10.11.1.3', '2')
  627.         self._test_version('4.0.1.3.dfsg.1-2', None, '4.0.1.3.dfsg.1', '2')
  628.         self._test_version('0.4.23debian1', None, '0.4.23debian1', None)
  629.         self._test_version('1.2.10+cvs20060429-1', None, '1.2.10+cvs20060429', '1')
  630.         self._test_version('0.2.0-1+b1', None, '0.2.0', '1+b1')
  631.         self._test_version('4.3.90.1svn-r21976-1', None, '4.3.90.1svn-r21976', '1')
  632.         self._test_version('1.5+E-14', None, '1.5+E', '14')
  633.         self._test_version('20060611-0.0', None, '20060611', '0.0')
  634.         self._test_version('0.52.2-5.1', None, '0.52.2', '5.1')
  635.         self._test_version('7.0-035+1', None, '7.0', '035+1')
  636.         self._test_version('1.1.0+cvs20060620-1+2.6.15-8', None, '1.1.0+cvs20060620-1+2.6.15', '8')
  637.         self._test_version('1.1.0+cvs20060620-1+1.0', None, '1.1.0+cvs20060620', '1+1.0')
  638.         self._test_version('4.2.0a+stable-2sarge1', None, '4.2.0a+stable', '2sarge1')
  639.         self._test_version('1.8RC4b', None, '1.8RC4b', None)
  640.         self._test_version('0.9~rc1-1', None, '0.9~rc1', '1')
  641.         self._test_version('2:1.0.4+svn26-1ubuntu1', '2', '1.0.4+svn26', '1ubuntu1')
  642.         self._test_version('2:1.0.4~rc2-1', '2', '1.0.4~rc2', '1')
  643.  
  644.     
  645.     def test_version_updating(self):
  646.         v = Version('1:1.4.1-1')
  647.         v.debian_version = '2'
  648.         self.assertEqual(v.debian_version, '2')
  649.         self.assertEqual(v.full_version, '1:1.4.1-2')
  650.         v.upstream_version = '1.4.2'
  651.         self.assertEqual(v.upstream_version, '1.4.2')
  652.         self.assertEqual(v.full_version, '1:1.4.2-2')
  653.         v.epoch = '2'
  654.         self.assertEqual(v.epoch, '2')
  655.         self.assertEqual(v.full_version, '2:1.4.2-2')
  656.         self.assertEqual(str(v), v.full_version)
  657.         v.full_version = '1:1.4.1-1'
  658.         self.assertEqual(v.full_version, '1:1.4.1-1')
  659.         self.assertEqual(v.epoch, '1')
  660.         self.assertEqual(v.upstream_version, '1.4.1')
  661.         self.assertEqual(v.debian_version, '1')
  662.  
  663.  
  664. if __name__ == '__main__':
  665.     _test()
  666.  
  667.